/**
 * Vision Analyzer Health Checker
 *
 * Provides comprehensive health monitoring for production deployment
 */

const fs = require('fs');
const path = require('path');
const { getLogger } = require('../logging/logger');
const { ErrorFactory } = require('../utils/errors');

class HealthChecker {
    constructor(configManager) {
        this.configManager = configManager;
        this.logger = getLogger('health-checker');
        this.startTime = Date.now();
        this.lastHealthCheck = null;
        this.healthStatus = {
            status: 'starting',
            uptime: 0,
            version: require('../../package.json').version,
            checks: {}
        };
    }

    /**
     * Perform comprehensive health check
     */
    async checkHealth() {
        const startTime = Date.now();

        try {
            this.logger.debug('Starting comprehensive health check');

            const checks = {
                uptime: this.checkUptime(),
                memory: this.checkMemory(),
                configuration: await this.checkConfiguration(),
                providers: await this.checkProviders(),
                filesystem: this.checkFilesystem(),
                dependencies: this.checkDependencies()
            };

            const overallStatus = Object.values(checks).every(check => check.status === 'healthy')
                ? 'healthy'
                : Object.values(checks).some(check => check.status === 'unhealthy')
                    ? 'unhealthy'
                    : 'degraded';

            this.healthStatus = {
                status: overallStatus,
                uptime: Date.now() - this.startTime,
                version: require('../../package.json').version,
                timestamp: new Date().toISOString(),
                duration: Date.now() - startTime,
                checks
            };

            this.lastHealthCheck = Date.now();

            if (overallStatus === 'healthy') {
                this.logger.info('Health check passed', { duration: this.healthStatus.duration });
            } else {
                this.logger.warn('Health check issues detected', { status: overallStatus, checks });
            }

            return this.healthStatus;

        } catch (error) {
            this.healthStatus.status = 'unhealthy';
            this.healthStatus.error = error.message;

            this.logger.error('Health check failed', { error: error.message, stack: error.stack });

            return this.healthStatus;
        }
    }

    /**
     * Check service uptime
     */
    checkUptime() {
        const uptime = Date.now() - this.startTime;
        const uptimeMinutes = Math.floor(uptime / 60000);

        return {
            status: uptimeMinutes > 0 ? 'healthy' : 'starting',
            uptime: uptime,
            uptimeMinutes: uptimeMinutes,
            message: `Service has been running for ${uptimeMinutes} minutes`
        };
    }

    /**
     * Check memory usage
     */
    checkMemory() {
        const usage = process.memoryUsage();
        const usedMB = Math.round(usage.heapUsed / 1024 / 1024);
        const totalMB = Math.round(usage.heapTotal / 1024 / 1024);
        const maxMB = Math.round(usage.heapTotal / 1024 / 1024 * 1.5); // Estimated max

        // Warning threshold: 80% of estimated max
        const warningThreshold = maxMB * 0.8;
        const criticalThreshold = maxMB * 0.95;

        let status = 'healthy';
        let message = `Memory usage: ${usedMB}MB / ${totalMB}MB`;

        if (usedMB > criticalThreshold) {
            status = 'unhealthy';
            message += ' - CRITICAL: Memory usage too high';
        } else if (usedMB > warningThreshold) {
            status = 'degraded';
            message += ' - WARNING: Memory usage high';
        }

        return {
            status,
            usage: {
                heapUsed: usage.heapUsed,
                heapTotal: usage.heapTotal,
                external: usage.external,
                rss: usage.rss
            },
            usageMB: {
                used: usedMB,
                total: totalMB,
                max: maxMB
            },
            message
        };
    }

    /**
     * Check configuration validity
     */
    async checkConfiguration() {
        try {
            const config = this.configManager.getConfig();
            const requiredFields = ['current_provider_model', 'providers'];

            const missing = requiredFields.filter(field => !config[field]);

            if (missing.length > 0) {
                return {
                    status: 'unhealthy',
                    message: `Missing configuration: ${missing.join(', ')}`,
                    missing
                };
            }

            // Validate provider configuration
            let providers;
            if (typeof config.providers === 'string') {
                providers = JSON.parse(config.providers);
            } else if (Array.isArray(config.providers)) {
                providers = config.providers;
            } else {
                providers = Object.keys(config.providers || {});
            }

            const hasValidProviders = providers.some(provider => {
                const providerConfig = config[provider];
                return providerConfig && providerConfig.api_key && providerConfig.api_key !== 'your-api-key-here';
            });

            if (!hasValidProviders) {
                return {
                    status: 'unhealthy',
                    message: 'No valid provider configuration found',
                    providers: providers.map(p => ({ name: p, configured: !!config[p]?.api_key }))
                };
            }

            return {
                status: 'healthy',
                message: 'Configuration is valid',
                currentProvider: config.current_provider_model,
                availableProviders: providers
            };

        } catch (error) {
            return {
                status: 'unhealthy',
                message: `Configuration error: ${error.message}`,
                error: error.message
            };
        }
    }

    /**
     * Check provider connectivity
     */
    async checkProviders() {
        try {
            const config = this.configManager.getConfig();

            let providers;
            if (typeof config.providers === 'string') {
                providers = JSON.parse(config.providers);
            } else if (Array.isArray(config.providers)) {
                providers = config.providers;
            } else {
                providers = Object.keys(config.providers || {});
            }

            const results = [];

            for (const providerName of providers) {
                const providerConfig = config[providerName];

                if (!providerConfig || !providerConfig.api_key || providerConfig.api_key.includes('your-')) {
                    results.push({
                        name: providerName,
                        status: 'unconfigured',
                        message: 'API key not configured'
                    });
                    continue;
                }

                // Basic connectivity check (ping-like)
                try {
                    const startTime = Date.now();
                    const response = await this.pingProvider(providerConfig.base, 5000);
                    const responseTime = Date.now() - startTime;

                    results.push({
                        name: providerName,
                        status: response.ok ? 'healthy' : 'unhealthy',
                        responseTime,
                        message: response.ok ? 'Provider reachable' : 'Provider unreachable'
                    });
                } catch (error) {
                    results.push({
                        name: providerName,
                        status: 'unhealthy',
                        message: `Connectivity failed: ${error.message}`
                    });
                }
            }

            const overallStatus = results.every(r => r.status === 'healthy') ? 'healthy' :
                                 results.some(r => r.status === 'unhealthy') ? 'unhealthy' : 'degraded';

            return {
                status: overallStatus,
                providers: results,
                message: `${results.filter(r => r.status === 'healthy').length}/${results.length} providers healthy`
            };

        } catch (error) {
            return {
                status: 'unhealthy',
                message: `Provider check failed: ${error.message}`,
                error: error.message
            };
        }
    }

    /**
     * Check filesystem accessibility
     */
    checkFilesystem() {
        try {
            const checks = [
                { path: process.cwd(), type: 'read' },
                { path: require('os').tmpdir(), type: 'write' }
            ];

            const results = checks.map(check => {
                try {
                    if (check.type === 'read') {
                        fs.accessSync(check.path, fs.constants.R_OK);
                    } else {
                        const testFile = path.join(check.path, 'vision-analyzer-test');
                        fs.writeFileSync(testFile, 'test');
                        fs.unlinkSync(testFile);
                    }

                    return { path: check.path, status: 'accessible' };
                } catch (error) {
                    return {
                        path: check.path,
                        status: 'inaccessible',
                        error: error.message
                    };
                }
            });

            const allAccessible = results.every(r => r.status === 'accessible');

            return {
                status: allAccessible ? 'healthy' : 'unhealthy',
                checks: results,
                message: allAccessible ? 'Filesystem accessible' : 'Filesystem issues detected'
            };

        } catch (error) {
            return {
                status: 'unhealthy',
                message: `Filesystem check failed: ${error.message}`,
                error: error.message
            };
        }
    }

    /**
     * Check critical dependencies
     */
    checkDependencies() {
        try {
            const criticalDeps = ['@modelcontextprotocol/sdk'];
            const results = [];

            for (const dep of criticalDeps) {
                try {
                    // Try multiple ways to check if module is available
                    let available = false;

                    try {
                        require.resolve(dep);
                        available = true;
                    } catch (e1) {
                        // Try direct require
                        try {
                            require(dep);
                            available = true;
                        } catch (e2) {
                            // Check package.json
                            const packageJson = require('../../package.json');
                            if (packageJson.dependencies && packageJson.dependencies[dep]) {
                                available = true;
                            }
                        }
                    }

                    results.push({
                        name: dep,
                        status: available ? 'available' : 'missing',
                        error: available ? null : 'Module not found in any location'
                    });
                } catch (error) {
                    results.push({
                        name: dep,
                        status: 'missing',
                        error: error.message
                    });
                }
            }

            const allAvailable = results.every(r => r.status === 'available');

            return {
                status: allAvailable ? 'healthy' : 'unhealthy',
                dependencies: results,
                message: allAvailable ? 'All dependencies available' : 'Missing dependencies detected'
            };

        } catch (error) {
            return {
                status: 'unhealthy',
                message: `Dependency check failed: ${error.message}`,
                error: error.message
            };
        }
    }

    /**
     * Simple ping to check provider connectivity
     */
    async pingProvider(baseUrl, timeout = 5000) {
        const https = require('https');
        const http = require('http');
        const url = require('url');

        return new Promise((resolve, reject) => {
            const parsedUrl = new URL(baseUrl);
            const client = parsedUrl.protocol === 'https:' ? https : http;

            const req = client.request({
                hostname: parsedUrl.hostname,
                port: parsedUrl.port || (parsedUrl.protocol === 'https:' ? 443 : 80),
                path: '/',
                method: 'HEAD',
                timeout: timeout
            }, (res) => {
                resolve({ ok: res.statusCode < 500, status: res.statusCode });
            });

            req.on('error', reject);
            req.on('timeout', () => {
                req.destroy();
                reject(new Error('Request timeout'));
            });

            req.end();
        });
    }

    /**
     * Get current health status (cached)
     */
    getHealthStatus() {
        return this.healthStatus;
    }

    /**
     * Get basic readiness status
     */
    isReady() {
        return this.healthStatus.status === 'healthy' &&
               (Date.now() - this.startTime) > 5000; // At least 5 seconds uptime
    }

    /**
     * Get basic liveness status
     */
    isAlive() {
        return this.healthStatus.status !== 'unhealthy';
    }
}

module.exports = HealthChecker;